﻿

// MappingGeneratorPro.LicenseManager
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Http;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
// using EnvDTE;
// using MappingGenerator.Features.Refactorings;
// using MappingGeneratorPro;
// using Microsoft.VisualStudio.Shell;
using Microsoft.Win32;

internal static class LicenseManager
{
    internal class ActivateLicenseResponse
	{
		public bool Activated { get; set; }

		public string Reason { get; set; }

		public Dictionary<string, string> Capabilities { get; set; }
	}

	public class ActivateLicenseRequest
	{
		public string Email { get; set; }

		public string LicenseKey { get; set; }

		public string ProductVersion { get; set; }

		public string VsVersion { get; set; }
	}

	public class License
	{
		public string HashedLicenseKey { get; set; }

		/// <summary>
		/// 激活时间，格式：yyyy-MM-dd
		/// </summary>
		public string ActivatedOn { get; set; }

		public string RegisteredProductVersion { get; set; }
		
		public string ThumbPrint { get; set; }

		public string ProductName { get; set; }

		public string ExpirationMessage => "Your subscription for MappingGenerator Upgrades expired. Please downgrade your MappingGenerator version to v" + RegisteredProductVersion + "  or active license key upgrade.";

		public bool IsActive()
		{
			if (IsValid())
			{
				return !IsExpired();
			}
			return false;
		}

		public bool IsExpired()
		{
			if (IsUnlimited())
			{
				return false;
			}
			if (string.IsNullOrWhiteSpace(ActivatedOn))
			{
				return true;
			}
			if (GetUpgradeSubscriptionExpiryDate() < DateTime.UtcNow && GetProductVersion() != RegisteredProductVersion)
			{
				return true;
			}
			return false;
		}

		private bool IsUnlimited()
		{
			return "Unlimited".Equals(RegisteredProductVersion, StringComparison.InvariantCultureIgnoreCase);
		}

		private DateTime GetUpgradeSubscriptionExpiryDate()
		{
			return DateTime.ParseExact(ActivatedOn, "yyyy-MM-dd", CultureInfo.InvariantCulture).AddDays(366.0);
		}

		public string CalculateThumbPrint()
		{
			string name = WindowsIdentity.GetCurrent().Name;
			string vsCurrentVersion = GetVsCurrentVersion();
			return CalculateHash(ActivatedOn + "||" + HashedLicenseKey + "||" + RegisteredProductVersion + "||" + name + "||" + vsCurrentVersion);
		}

		public bool IsValid()
		{
			return ThumbPrint == CalculateThumbPrint();
		}

		public string GetUpgradeSubscriptionInfo()
		{
			if (IsUnlimited())
			{
				return "Unlimited";
			}
			DateTime upgradeSubscriptionExpiryDate = GetUpgradeSubscriptionExpiryDate();
			if (upgradeSubscriptionExpiryDate < DateTime.UtcNow)
			{
				return "No";
			}
			return $"until {upgradeSubscriptionExpiryDate:yyyy-MM-dd}";
		}
	}

	//Call FROM MappingGeneratorPro.LicenseDialogViewModel.ActivateLicenseCommand
	public static async Task<LicenseActivationResult> TryToActivate(string email, string licenseKey)
	{
		ActivateLicenseRequest activationData = new ActivateLicenseRequest
		{
			Email = email,
			LicenseKey = licenseKey,
			ProductVersion = GetProductVersion(),
			VsVersion = GetVsCurrentVersion()
		};
		ActivateLicenseResponse activateLicenseResponse = await RequestActivation(activationData).ConfigureAwait(continueOnCapturedContext: false);
		if (activateLicenseResponse.Activated)
		{
			if (TrySaveLicenseInfo(activationData, activateLicenseResponse))
			{
				return LicenseActivationResult.Success();
			}
			return LicenseActivationResult.Fail("Cannot save activation data. Please try to run VisualStudio as Administrator");
		}
		return LicenseActivationResult.Fail(activateLicenseResponse.Reason);
	}

	private static async Task<ActivateLicenseResponse> RequestActivation(ActivateLicenseRequest activationData)
	{
		int leftAttempt = 5;
		HttpClient httpClient = new HttpClient();
		try
		{
			ActivateLicenseResponse result = new ActivateLicenseResponse();
			do
			{
				try
				{
					HttpResponseMessage val = await httpClient.PostAsJsonAsync("https://mappinggeneratorlicenseservertest.azurewebsites.net/api/ActivateLicense", activationData).ConfigureAwait(continueOnCapturedContext: false);
					if (val.IsSuccessStatusCode)
					{
						result = await val.Content.ReadAsAsync<ActivateLicenseResponse>().ConfigureAwait(continueOnCapturedContext: false);
						if (result.Activated)
						{
							return result;
						}
					}
				}
				catch
				{
				}
				leftAttempt--;
				await Task.Delay(10000).ConfigureAwait(continueOnCapturedContext: false);
			}
			while (leftAttempt > 0);
			return result;
		}
		finally
		{
			((IDisposable)httpClient)?.Dispose();
		}
	}

	internal static string GetProductVersion()
	{
		//Version version = typeof(MappingGeneratorRefactoring).Assembly.GetName().Version;
		return $"{2021}.{6}";
	}

	public static string GetProductFullVersion()
	{
		//return typeof(MappingGeneratorRefactoring).Assembly.GetName().Version.ToString();
        return "2021.6.8.0";
    }

	internal static string GetVsCurrentVersion()
	{
		// return ((DTE)Package.GetGlobalService(typeof(DTE))).Version switch
		// {
		// 	"15.0" => "Vs2017",
		// 	"16.0" => "Vs2019",
		// 	"17.0" => "Vs2022",
		// 	_ => string.Empty,
		// };

        return "Vs2019";
    }

	internal static string CalculateHash(string s)
	{
		using SHA256 sHA = SHA256.Create();
		byte[] array = sHA.ComputeHash(Encoding.UTF8.GetBytes(s));
		StringBuilder stringBuilder = new StringBuilder();
		byte[] array2 = array;
		foreach (byte b in array2)
		{
			stringBuilder.Append(b.ToString("x2"));
		}
		return stringBuilder.ToString();
	}

	private static bool CanUseWithCurrentProduct(ActivateLicenseResponse result)
	{
		string vsCurrentVersion = GetVsCurrentVersion();
		if (!result.Capabilities["VsVersion"].Equals("Unlimited", StringComparison.InvariantCultureIgnoreCase))
		{
			return vsCurrentVersion.Equals(result.Capabilities["VsVersion"], StringComparison.InvariantCultureIgnoreCase);
		}
		return true;
	}

	public static bool IsFirstTimeExperience()
	{
		string vsCurrentVersion = GetVsCurrentVersion();
		RegistryKey registryKey = AccessRegistryKeyForEdit(Registry.CurrentUser, "Software", "MappingGenerator", vsCurrentVersion);
		if (registryKey != null && (string)registryKey.GetValue("FirstTimeExperience", "True") == bool.TrueString)
		{
			return true;
		}
		return false;
	}

	public static void MarkFirstTimeExperience()
	{
		string vsCurrentVersion = GetVsCurrentVersion();
		AccessRegistryKeyForEdit(Registry.CurrentUser, "Software", "MappingGenerator", vsCurrentVersion)?.SetValue("FirstTimeExperience", false);
	}

	internal static bool TrySaveLicenseInfo(ActivateLicenseRequest activationData, ActivateLicenseResponse activationResult)
	{
		RegistryKey registryKey = AccessRegistryKeyForEdit(Registry.CurrentUser, "Software", "MappingGenerator", activationData.VsVersion);
		if (registryKey != null)
		{
			License license = new License
			{
				ActivatedOn = activationResult.Capabilities["ActivatedOn"],
				HashedLicenseKey = CalculateHash(activationData.LicenseKey),
				RegisteredProductVersion = activationResult.Capabilities["RegisteredProductVersion"],
				ProductName = activationResult.Capabilities["Product"]
			};
			registryKey.SetValue("Product", license.ProductName, RegistryValueKind.String);
			registryKey.SetValue("LicenseKey", license.HashedLicenseKey, RegistryValueKind.String);
			registryKey.SetValue("ActivatedOn", license.ActivatedOn, RegistryValueKind.String);
			registryKey.SetValue("RegisteredProductVersion", license.RegisteredProductVersion, RegistryValueKind.String);
			registryKey.SetValue("ThumbPrint", license.CalculateThumbPrint(), RegistryValueKind.String);
			return true;
		}
		return false;
	}

	internal static RegistryKey AccessRegistryKeyForEdit(RegistryKey root, params string[] path)
	{
		RegistryKey registryKey = root;
		foreach (string text in path)
		{
			if (registryKey == null)
			{
				return null;
			}
			registryKey = registryKey.OpenSubKey(text, writable: true) ?? registryKey.CreateSubKey(text, writable: true);
		}
		return registryKey;
	}

	public static bool HasActiveLicense()
	{
		return GetLicenseData()?.IsActive() ?? false;
	}

	//关键函数
	//CALL FROM MappingGeneratorPro.LicenseDialogViewModel.RefreshLicenseInfo
	public static License GetLicenseData()
	{
		string vsCurrentVersion = GetVsCurrentVersion();
		RegistryKey registryKey = AccessRegistryKeyForRead(Registry.CurrentUser, "Software", "MappingGenerator", vsCurrentVersion);
		if (registryKey != null)
		{
			string text = registryKey.GetValue("Product") as string;
			if (text != null)
			{
				string text2 = registryKey.GetValue("LicenseKey") as string;
				if (text2 != null)
				{
					string text3 = registryKey.GetValue("ActivatedOn") as string;
					if (text3 != null)
					{
						string text4 = registryKey.GetValue("RegisteredProductVersion") as string;
						if (text4 != null)
						{
							string text5 = registryKey.GetValue("ThumbPrint") as string;
							if (text5 != null)
							{
								return new License
								{
									ActivatedOn = text3,
									RegisteredProductVersion = text4,
									HashedLicenseKey = text2,
									ThumbPrint = text5,
									ProductName = text
								};
							}
						}
					}
				}
			}
		}
		return null;
	}

	private static RegistryKey AccessRegistryKeyForRead(RegistryKey root, params string[] path)
	{
		RegistryKey registryKey = root;
		foreach (string name in path)
		{
			if (registryKey == null)
			{
				return null;
			}
			registryKey = registryKey.OpenSubKey(name, writable: true);
		}
		return registryKey;
	}
}
